/*
* Copyright (c) 2008-2011, Thomas Handorf
* 
* This file is part of libScopes.
* libScopes is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* 
* libScopes is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU Lesser General Public License
* along with libScopes.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef th_array_h
#define th_array_h

#include <stdio.h>
#include <vector>
#include <string>
#include <algorithm>
#ifdef SCOPES_USEBOOSTSERIALIZATION
#include <boost/serialization/version.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/nvp.hpp>
#endif // SCOPES_USEBOOSTSERIALIZATION
#include <iostream>
//#include "serialization.h"


/*! \brief Template class for an Array of type T based on a STL vector.

	Provides routines for manipulating the vector, inlcuding arithmetical (i.e. adding) and logical (i.e. AND, OR) and set operations.
	Contains routines to insert and overwrite data without using iterators. 
*/
#ifndef SWIG
typedef std::vector<int>::size_type size_type; // this should also hold for other relevant elements types than int
template <class T> bool TisReal(){ //specializations in array.cpp
   return false;
}

#endif
template <class T> class array : public std::vector<T>{
	public:

		//! \name Constructors
		//@{
      array();
		array(size_type size);
      array(size_type size, const T& val);
		array(const array &ar2);
      array(const std::vector<T> &v2);
      array(size_type size,const T* ar2);
      template <class InputIterator>
         array ( InputIterator first, InputIterator last) : std::vector<T>(first,last) {};
//		array(const std::string &str);
//		array(const std::string &str, size_type pos);
		~array();
		//@}		
		
		//! \name Vector wrapper functions
		//@{
		using std::vector<T>::insert;
      void insert(size_type idx, const array<T>& ar2);
      void insert(size_type idx, size_type len, const T& val);
      using std::vector<T>::erase;
		void erase(size_type idx, size_type len);
      using std::vector<T>::assign;
      void assign(const array<T>& ar2);
      //@}
		
		//! \name Operations on complete array
		//@{
		std::string printToString();
		void print();
//      std::string toString();
// 	  void serialize(std::string& str);
//      void deserialize(std::string& str,size_type& pos);
		template <class T2> array<T2>* convertTo();//!< convert into array of different type
		//@}

		//! \name Array copy & paste, etc.
		//@{
		array<T>* copy();//!< return a copy of the array
      template <class T2> void put(const array<T2>& ar2);
      template <class T2> void put(size_type idx,const array<T2>& ar2);
      template <class T2> void put(size_type idx,const array<T2>& ar2, size_type num);
      void fill(const T& val);
      void put(size_type idx, const T& val);
      void put(size_type idx, const T& val, size_type num);
      template <class T2> void replace(size_type idx, size_type len,const array<T2>& ar2,size_type idx2=0, size_type num=-1);
      template <class T2> void replace(size_type idx, const array<T2>& ar2,size_type idx2=0, size_type num=-1);
      void replace(size_type idx, size_type len,const T& val,size_type num);
      void replace(size_type idx, const T& val,size_type num);
      void selectPut(array<size_type> &idxs,const T& val);//!<fill elements indexed by idxs array with val
      template <class T2> void selectPut(array<size_type> &idxs,const array<T2>& ar2);//!<fill elements indexed by idxs array with elements from ar2
		array<T>* selectGet( array<size_type> &idxs );//!<get values of current array indexed by idxs
		void crop(size_type idx, size_type len);
      void random(T max);
      void random(T min,T max);;//!<fill array with random number in [min,max)
		//@}

		//! \name Array inspection
		//@{
		int find(const T& val);
      int find(size_type idx, const T& val);
      int findNe(const T&  val);
      int findNe(size_type idx, const T&  val);
		T at(size_type idx);
		T max();
		T min();
		array<size_type>* which();//!<returns indices of non-zero elements
      array<size_type>* whichEq(const T& val);//!<returns indices of elements equal to val
      array<size_type>* whichLt(const T& val);//!<returns indices of elements less than val
      array<size_type>* whichLe(const T& val);//!<returns indices of elements less than or equal to val
      array<size_type>* whichGt(const T& val);//!<returns indices of elements greater than val
      array<size_type>* whichGe(const T& val);//!<returns indices of elements greater than or equal to val
		//@}
		
		//! \name component wise operations
		//@{
		size_type nz();//!< number of non-zero elements
		//~ void scale(T mult);//!< multiply all components by mult
		template <class T2> void add(array<T2>& ar2);//!< add second array component by component
		template <class T2> void add(array<T2>& ar2,T mult);//!< add second array multiplied by mult component by component
		template <class T2> void sub(array<T2>& ar2);//!< subtract second array component by component
      template <class T2> bool isEq(array<T2>& ar2);//!< equal?
      template <class T2> bool isSubsetOf(array<T2>& ar2);//!< true if current array has zeros wherever ar2 has zeroes
      template <class T2> bool isSetEq(array<T2>& ar2);//!< boolean equal
		template <class T2> void AND(array<T2>& ar2);//!< combine arrays using AND operator (boolean)
      template <class T2> size_type ANDnz(array<T2>& ar2);//!< size of cutset (boolean)
      template <class T2> void OR(array<T2>& ar2);//!< combine arrays using OR operator (boolean)
      template <class T2> size_type ORnz(array<T2>& ar2);//!< size of set union (boolean) 
      template <class T2> void XOR(array<T2>& ar2);//!< combine arrays using XOR operator (boolean)
      template <class T2> size_type XORnz(array<T2>& ar2);//!< size of XOR set (boolean)
      template <class T2> void subSet(array<T2>& ar2);//!< substract(boolean) ar2 from current array 
		template <class T2> size_type subSetnz(array<T2>& ar2);//!< size of set substraction (substract(boolean) ar2 from current array)
		//@}
#ifdef SCOPES_USEBOOSTSERIALIZATION
		friend class boost::serialization::access;
		template<class Archive> void serialize(Archive & ar, const unsigned int version) {
		  ar & boost::serialization::make_nvp("array",boost::serialization::base_object<std::vector<T> >(*this));
		}
#endif // SCOPES_USEBOOSTSERIALIZATION
};

#ifndef SWIG // everything else should be ignored by SWIG
template <typename T> std::string array_print( array<T>& ar ) {
   size_type len=ar.size();
   size_type i;
   std::string str;
   char charstr[50];
   str.append("[");
   for (i=0;i<len;i++){
      sprintf(charstr,"%ld ",(long int) ar[i]);
      str.append(charstr);
   }
   if (len) str.erase(str.length()-1,1);
   str.append("]");
   return str;
}
template <typename T> std::string array_print( array< array<T>* >& ar ) {
   size_type len=ar.size();
   size_type i;
   std::string str;
   std::string str2;
   str.append("[\n");
   for (i=0;i<len;i++){
      str2=ar[i]->printToString();
      str.append(str2);
      str.append(",\n");
   }
   if (len) str.erase(str.length()-2,2);
   str.append("\n]");
   return str;
}
std::string array_print( array<double> & ar ); // needs to be implemented in array.cpp as it is no template
std::string array_print( array<float> & ar ); // needs to be implemented in array.cpp as it is no template


//! Default constructor.
template <class T> array<T>::array(){
#ifdef DEBUG
	printf("array: standard constructor \n");fflush(stdout);
#endif
}
//! Constructor: allocate size elements.
template <class T> array<T>::array(size_type size): std::vector<T>(size){
#ifdef DEBUG
	printf("array: standard constructor with size\n");fflush(stdout);
#endif
}
//! Constructor: fill size elements with val.
template <class T> array<T>::array(size_type size, const T& val) : std::vector<T>(size,val){
#ifdef DEBUG
	printf("array: standard constructor with fill \n");fflush(stdout);
#endif
}

//! Copy constructor.
template <class T> array<T>::array(const array<T> &ar2) : std::vector<T>(ar2){
	
#ifdef DEBUG
	printf("array: copy constructor \n");fflush(stdout);
#endif
/*   this->assign(ar2.begin(),ar2.end());*/
}
template <class T> array<T>::array(const std::vector<T> &v2) : std::vector<T>(v2){
   
#ifdef DEBUG
   printf("array: copy constructor \n");fflush(stdout);
#endif
/*   this->assign(ar2.begin(),ar2.end());*/
}
//! constructor with T* array.
template <class T> array<T>::array(size_type size,const T* ar2){
	
#ifdef DEBUG
	printf("array: T* constructor \n");fflush(stdout);
#endif
	size_type i;
	this->resize(size);
   for (i=0;i<size;i++) {
      (*this)[i] = (T) ar2[i];
   }
}
	

/*//! std::string constructor
template <class T> array<T>::array(const std::string &str){
	
	size_type pos=0;
	array(str,pos);
}
//! std::string constructor with position in std::string
template <class T> array<T>::array(const std::string &str, size_type &pos){
	
	size_type len;
	str.copy((char*) &len,sizeof(len),pos);pos+=sizeof(len);
#ifdef DEBUG
	printf("array: std::string constructor (pos=%ld,num=%ld)\n",pos-sizeof(len),len/sizeof(T));fflush(stdout);
#endif
	this->resize(len/sizeof(T));
	str.copy((char*) &(this->front()),len,pos);
	pos+=len;
}*/
//! Destructor.
template <class T> array<T>::~array(){
#ifdef DEBUG
	printf("array: destructor \n");fflush(stdout);
#endif
}


// vector wrappers

/* \brief access element at index idx
\param idx element index to access
*/
/*template <class T> inline T& array<T>::operator[](size_type idx){
	return (this->_M_impl._M_start)[idx];
}
template <class T> inline const T& array<T>::operator[](size_type idx) const{
	return (this->_M_impl._M_start)[idx];
}

template <class T> inline T& array<T>::front(){
	return *(this->_M_impl._M_start);
}
template <class T> inline const T& array<T>::front() const{
	return *(this->_M_impl._M_start);
}

template <class T> inline T& array<T>::back(){
	return *(this->_M_impl._M_finish);
}
template <class T> inline const T& array<T>::back() const{
	return *(this->_M_impl._M_finish);
}*/

/*template <class T> inline size_type array<T>::size() const{
	return (size_type) ((size_t) this->_M_impl._M_finish - (size_t)  this->_M_impl._M_start) / sizeof(T);
}*/
// template <class T> inline size_type array<T>::size() const{
//    size_t s=this->size();
//    return (size_type) s;
// }

template <class T> inline void array<T>::insert(size_type idx, size_type len, const T& val){
   this->insert(this->begin()+idx,len,val);
}
template <class T> inline void array<T>::insert(size_type idx, const array<T>& ar2){
   this->insert(this->begin()+idx,ar2.begin(),ar2.end());
}
template <class T> inline void array<T>::erase(size_type idx, size_type len){
	this->erase(this->begin()+idx,this->begin()+idx+len);
}
template <class T> inline void array<T>::assign(const array<T>& ar2){
   this->assign(ar2.begin(),ar2.end());
}



// array methods

/*!
	\brief Put new data in current array
	\param ar2 array containing the new data 
	
	Array ar2 is put at position 0 of the this array, overwriting the current content. The length of this array is increased if ar2 is larger than the current array.
*/
template <class T> template <class T2> inline void array<T>::put(const array<T2>& ar2){
	put(0,ar2);
}

/*!
	\overload
	\param idx index at which ar2 should be placed
	\param ar2 array containing the data to replace
	
	Array ar2 is put at position idx of the this array, overwriting the current content. The length of this array is increased if len(ar2)+idx is larger than the current array.
*/
template <class T> template <class T2> inline void array<T>::put(size_type idx, const array<T2>& ar2){
   put(idx,ar2,ar2.size());
}

/*!
	\overload
	\param idx index at which ar2 should be placed
	\param ar2 array containing the data to replace
	\param num length of the part which should be replaced
	
	Array ar2 is put at position idx of the this array, overwriting the current content (up to len elements). The length of this array is increased if idx+len is larger that the current length. In the current array, len elements are reserved even if the length of ar2 is shorter.
*/
template <class T> template <class T2> void array<T>::put(size_type idx,const array<T2>& ar2, size_type num){
   size_type i,n,len2;
   if (this->size()<num+idx) this->resize(num+idx);
   len2=ar2.size();
   for (i=0;i<num;i++) {
      n=i % len2; // repeat ar2 if it is too short
      (*this)[i+idx] = (T) ar2[n];
   }
}


/*!
	\overload
	\param idx index at which ar2 should be placed
	\param len length of the part which should be replaced
	\param ar2 array containing the data to replace
	\param idx2 index in ar2 where copying starts
	\param num how many elements from ar2
	
	Note: everything from idx to idx+len of the array is replaced by ar2.
	The length of the array is changed accordingly.
*/
template <class T> template <class T2> void array<T>::replace(size_type idx, size_type len,const array<T2>& ar2,size_type idx2, size_type num){
   this->erase(idx,len);
   this->insert(idx,ar2.begin()+idx2,ar2.begin()+idx2+num);
}

/*!
\overload
\param idx index at which ar2 should be placed
\param ar2 array containing the data to replace
\param idx2 index in ar2 where copying starts
\param num how many elements from ar2

Note: everything from idx to the end of the array is replaced by ar2.
The length of the array is changed accordingly.
*/
template <class T> template <class T2> void array<T>::replace(size_type idx, const array<T2>& ar2,size_type idx2, size_type num){
   this->erase(this->begin()+idx,this->end());
   this->insert(idx,ar2.begin()+idx2,ar2.begin()+idx2+num);
}

/*!
	\brief Put a single value in current array
	\param idx index at which the value should be placed
	\param val value to be set
	
	Put one element of value val at position idx.
	The length of the array is changed if idx >= length of current array.
*/
template <class T> inline void array<T>::put(size_type idx, const T& val){
   if (this->size()<idx+1) this->resize(idx+1);
   (*this)[idx]=val;
}

/*!
	\brief Fill the array with a single value
	\param val value with which part of the array should be filled
	\param idx index at which ar2 should be placed
	
	Everything from the beginning to the end of the array is filled with val.
*/
template <class T> inline void array<T>::fill(const T& val){
   put(0,val,this->size());
}

/*!
	\overload
	\param idx index at which ar2 should be placed
	\param val value with which part of the array should be filled
	\param num length of the part which should be replaced
	
	Everything from idx to idx+num of the array is filled with val.
	The length of the array is changed if idx+len is larger than the current len.
*/
template <class T> void array<T>::put(size_type idx,const T& val,size_type num){
   size_type i;
   if (this->size()<num+idx) this->resize(num+idx);
   for (i=0;i<num;i++) {
      (*this)[i+idx] = val;
   }
}

/*!
	\brief Replace the array by num values
	\param val value with which part of the array should be filled
	\param num number of values to be inserted
	
	Everything from the beginning to the end of the array is replaced by num values val.
	The length of the array will be num.
*/

/*!
\brief Replace part of the array by num values
\param idx index at which ar2 should be placed
\param len length of the array to be replaced
\param val value with which part of the array should be filled
\param num number of values to be inserted

everything from idx to idx+len of the array is replaced by num values.
The length of the array is changed acordingly.
*/
template <class T> void array<T>::replace(size_type idx, size_type len,const T& val,size_type num){
   erase(idx,len);
   insert(idx,num,val);
}
/*!
\brief Replace part of the array by num values
\param idx index at which ar2 should be placed
\param val value with which part of the array should be filled
\param num number of values to be inserted

everything from idx to the end of the array is replaced by num values.
The length of the array is changed acordingly.
*/
template <class T> void array<T>::replace(size_type idx, const T& val,size_type num){
   this->resize(idx+num);
   put(idx,val,num);
}

/*!
\brief crops array
\param idx index at which ar2 should start
\param len new length of array

new array contains all elements from idx to idx+len-1. idx can be negative in which case it is counted from the end. len<0 indicates 
how many elements to crop from  the end of the array. len=0 keeps everthing from idx up to the end.
*/
template <class T> void array<T>::crop(size_type idx, size_type len){
	size_type curlen=this->size();
	if (idx<0) idx=curlen+idx;
	if (idx<0) idx=0;
	if (len<=0) len=curlen-idx+len;
	if (len<0) {
		this->resize(0);
		return;
	}
	if (idx>0){
		if (idx>=curlen){
			this->resize(0);
			return;
		}
		this->erase(0,idx);
		curlen-=idx;
	}
	if (len>=curlen) return;
	this->resize(len);
}

template <class T> void array<T>::random(T max){
   return random((T)0,max);
}

template <class T> void array<T>::random(T min,T max){
   T diff=max-min;
   size_type len=this->size();
   size_type i;
   for (i=0;i<len;i++){
      if (TisReal<T>()){
         (*this)[i]=min+((T)rand())*diff/RAND_MAX;
      } else {
         (*this)[i]=min+(rand() % (long) diff); // assuming diff << RAND_MAX; the long is needed for compilation of T=float,double, although this will never be executed
      }
   }
}

// array inspection

/*!
	\brief Find position of a specific value 
	\param val value to be looked for
	
	Returns the index of the first element with value val in the array.
	Returns -1 of val is not found.
*/
template <class T> int array<T>::find(const T& val){
	return find(0,val);
}

/*!
	\overload
	\param val value to be looked for
	
	Returns the index of the first element after or at position idx with value val in the array.
	Returns -1 of val is not found.
*/
template <class T> int array<T>::find(size_type idx , const T& val){
	size_type curlen=this->size();
	size_type i;
	if (idx>=curlen) return -1;
	for (i=idx;i<curlen;i++){
		if ((*this)[i]==val) break;
	}
	if (i>=curlen) return -1;
	return (int) i;
}


/*!
	\brief Find position of a value not equal to the specific value 
	\param val value to be looked for
	
	Returns the index of the first element whose value is not val in the array.
	Returns -1 of value!=val is not found.
*/
template <class T> int array<T>::findNe(const T& val){
	return findNe(0,val);
}

/*!
	\overload
	\param val value to be looked for
	
	Returns the index of the first element after or at position idx whose value is not val in the array.
	Returns -1 of value!=val is not found.
*/
template <class T> int array<T>::findNe(size_type idx, const T& val ){
	size_type curlen=this->size();
	size_type i;
	if (idx>=curlen) return -1;
	for (i=idx;i<curlen;i++){
		if ((*this)[i]!=val) break;
	}
	if (i>=curlen) return -1;
	return (int) i;
}

/*!
	\brief Return element at specified position
	\param idx index of queried element
	
	returns reference to original element
*/
template <class T> T array<T>::at(size_type idx){
	return (*this)[idx];
}


/*!
	\brief maximum value of the array
	
	Note: returns (T) 0 if length of array is 0, so check length beforehand
*/
template <class T> T array<T>::max(){
	size_type curlen=this->size();
	size_type i;
	if (curlen<1) return 0;
	T mx=(*this)[0];
	for (i=0;i<curlen;i++){
		if ((*this)[i]>mx) mx=(*this)[i];
	}
	return mx;
}
/*!
	\brief minimum value of the array

	Note: returns (T) 0 if length of array is 0, so check length beforehand
*/
template <class T> T array<T>::min(){
	size_type curlen=this->size();
	size_type i;
	if (curlen<1) return 0;
	T mn=(*this)[0];
	for (i=0;i<curlen;i++){
		if ((*this)[i]<mn) mn=(*this)[i];
	}
	return mn;
}

/*!
	\brief prints the array to std::string

	Note: This only works for certain types T
*/
template <class T> std::string array<T>::printToString(){
   return array_print( *this );
//   return array_printer<T>::print( *this );
}
/*template <class T> std::string array<T>::printToString(){
	size_type len=this->size();
	size_type i;
	std::string str=new std::string();
	char charstr[50];
	str->append("[");
	for (i=0;i<len;i++){
		sprintf(charstr,"%ld ",(long int) (*this)[i]);
		str->append(charstr);
	}
	if (len) str->erase(str->length()-1,1);
	str->append("]");
	return str;
}
template <> inline std::string array<double>::printToString(){
	size_type len=this->size();
	size_type i;
	std::string str=new std::string();
	char charstr[50];
	str->append("[");
	for (i=0;i<len;i++){
		sprintf(charstr,"%g ",(*this)[i]);
		str->append(charstr);
	}
	if (len) str->erase(str->length()-1,1);
	str->append("]");
	return str;
}*/
/*template <class U> std::string array<array<U>*>::printToString(){
   size_type len=this->size();
   size_type i;
   std::string str=new std::string();
   std::string str2;
   char charstr[50];
   str->append("[\n");
   for (i=0;i<len;i++){
      str2=(*this)[i]->printToString();
      str->append(str2);
      str->append(",\n");
   }
   if (len) str->erase(str->length()-2,2);
   str->append("\n]");
   return str;
}*/
/*!
	\brief prints the array to stdout

	Note: This only works for certain types T
*/
template <class T> inline void array<T>::print(){
	std::cout << this->printToString() << std::endl;
//	printf("%s\n",this->printToString()->c_str);fflush(stdout);
}

/*//! creates a std::string containing a copy of the array data
template <class T> std::string array<T>::toString(){
	std::string str=new std::string();
	appendToString(*str);
	return str;
}*/
//! appends a copy of the array data to a std::string
/*template <class T> void array<T>::serialize(std::string& str){
	size_type len=this->size();
   size_type i;
   str.append((char*) &len,sizeof(len));
   if (serialization_info<T>::is_serializable){
      for (i=0;i<len;i++){
         if (serialization_info<T>::is_pointer){
            if (!(*this)[i]) (*this)[i]=new_from_pointer(); // make sure there is at least an empty something
            (*this)[i]->serialize(str);
         } else {
            (*this)[i].serialize(str);
         }
      }
   } else {
      str.append((char*) &(this->front()),len*sizeof(T)); 
   }
}*/
/*template <class T> void array<T>::deserialize(std::string& str,size_type& pos){
   size_type len;
   str.copy((char*) &len,sizeof(len),pos);
   pos+=sizeof(len);
   this->clear();
   this->resize(len);
   size_type i;
   if (serialization_info<T>::is_serializable){
      for (i=0;i<len;i++){
         if (serialization_info<T>::is_pointer){
            (*this)[i]=new_from_pointer();
            (*this)[i]->deserialize(str,pos);
         } else {
            (*this)[i].deserialize(str,pos);
         }
      }
   } else {
      str.copy((char*) &(this->front()),len*sizeof(T),pos);
      pos+=len*sizeof(T);
   }
}*/
template <class T> array<size_type>* array<T>::which(){
	size_type len=this->size();
	array<size_type>* ar2=new array<size_type>();
	ar2->reserve(len);
	size_type i;
	for (i=0;i<len;i++){
		if ((*this)[i]) ar2->push_back(i);
	}
	return ar2;
}
template <class T> array<size_type>* array<T>::whichEq(const T& val){
	size_type len=this->size();
	array<size_type>* ar2=new array<size_type>();
	ar2->reserve(len);
	size_type i;
	for (i=0;i<len;i++){
		if ((*this)[i]==val) ar2->push_back(i);
	}
	return ar2;
}
template <class T> array<size_type>* array<T>::whichLt(const T& val){
	size_type len=this->size();
	array<size_type>* ar2=new array<size_type>();
	ar2->reserve(len);
	size_type i;
	for (i=0;i<len;i++){
		if ((*this)[i]<val) ar2->push_back(i);
	}
	return ar2;
}
template <class T> array<size_type>* array<T>::whichLe(const T& val){
	size_type len=this->size();
	array<size_type>* ar2=new array<size_type>();
	ar2->reserve(len);
	size_type i;
	for (i=0;i<len;i++){
		if ((*this)[i]<=val) ar2->push_back(i);
	}
	return ar2;
}
template <class T> array<size_type>* array<T>::whichGt(const T& val){
	size_type len=this->size();
	array<size_type>* ar2=new array<size_type>();
	ar2->reserve(len);
	size_type i;
	for (i=0;i<len;i++){
		if ((*this)[i]>val) ar2->push_back(i);
	}
	return ar2;
}
template <class T> array<size_type>* array<T>::whichGe(const T& val){
	size_type len=this->size();
	array<size_type>* ar2=new array<size_type>();
	ar2->reserve(len);
	size_type i;
	for (i=0;i<len;i++){
		if ((*this)[i]>=val) ar2->push_back(i);
	}
	return ar2;
}
template <class T> void array<T>::selectPut(array<size_type> &idxs,const T& val){
	size_type i;
	size_type len=idxs.size();
	for (i=0;i<len;i++){
		(*this)[idxs[i]]=val;
	}
}
template <class T> template <class T2> void array<T>::selectPut(array<size_type> &idxs, const array<T2>& ar2){
	size_type i;
	size_type len=idxs.size();
	for (i=0;i<len;i++){
		(*this)[idxs[i]]=(T) ar2[i];
	}
}
template <class T> array<T>* array<T>::selectGet(array<size_type> &idxs){
	size_type i;
	size_type len=idxs.size();
	array<T>* ar2=new array<T>(len);
	for (i=0;i<len;i++){
		(*ar2)[i]=(*this)[idxs[i]];
	}
	return ar2;
}

template <class T> template <class T2> array<T2>* array<T>::convertTo(){
	size_type len=this->size();
	array<T2>* ar2=new array<T2>(len);
	size_type i;
	for (i=0;i<len;i++){
		(*ar2)[i]=(T2) (*this)[i];
	}
	return ar2;
}
template <class T> inline array<T>* array<T>::copy(){
	return new array<T>(*this);
}


template <class T> inline size_type array<T>::nz(){
	size_type i;
	size_type num=0;
	for (i=0;i<this->size();i++){
		if ((*this)[i]) num++;
	}
	return num;
}
template <class T> template <class T2> inline void array<T>::add(array<T2>& ar2){
	size_type len=std::min(this->size(),ar2.size());
	size_type i;
	for (i=0;i<len;i++){
		(*this)[i]+=(T) ar2[i];
	}
}
template <class T> template <class T2> inline void array<T>::sub(array<T2>& ar2){
	size_type len=std::min(this->size(),ar2.size());
	size_type i;
	for (i=0;i<len;i++){
		(*this)[i]-=(T) ar2[i];
	}
}
template <class T> template <class T2> inline void array<T>::add(array<T2>& ar2,T mult){
	size_type len=std::min(this->size(),ar2.size());
	size_type i;
	for (i=0;i<len;i++){
		(*this)[i]+=mult * (T) ar2[i];
	}
}
template <class T> template <class T2> inline bool array<T>::isSubsetOf(array<T2>& ar2){
	size_type len=std::min(this->size(),ar2.size());
	size_type i;
	for (i=0;i<len;i++){
		if ((*this)[i] && (!ar2[i])) return false;
	}
	return true;
}
template <class T> template <class T2> inline bool array<T>::isSetEq(array<T2>& ar2){
	size_type len=std::min(this->size(),ar2.size());
	size_type i;
	for (i=0;i<len;i++){
		if (((*this)[i] && (!ar2[i])) || ((!(*this)[i]) && (ar2[i]))) return false;
	}
	return true;
}
template <class T> template <class T2> inline bool array<T>::isEq(array<T2>& ar2){
   size_type len=std::min(this->size(),ar2.size());
   size_type i;
   for (i=0;i<len;i++){
      if ((*this)[i] != (T) ar2[i]) return false;
   }
   return true;
}
template <class T> template <class T2> inline void array<T>::AND(array<T2>& ar2){
	size_type len=std::min(this->size(),ar2.size());
	size_type i;
	for (i=0;i<len;i++){
		(*this)[i]=(*this)[i] && ar2[i];
	}
}
template <class T> template <class T2> inline size_type array<T>::ANDnz(array<T2>& ar2){
	size_type len=std::min(this->size(),ar2.size());
	size_type i;
	size_type num=0;
	for (i=0;i<len;i++){
		if ((*this)[i] && ar2[i]) num++;
	}
	return num;
}
template <class T> template <class T2> inline void array<T>::OR(array<T2>& ar2){
	size_type len=std::min(this->size(),ar2.size());
	size_type i;
	for (i=0;i<len;i++){
		(*this)[i]=(*this)[i] || ar2[i];
	}
}
template <class T> template <class T2> inline size_type array<T>::ORnz(array<T2>& ar2){
	size_type len=std::min(this->size(),ar2.size());
	size_type i;
	size_type num=0;
	for (i=0;i<len;i++){
		if ((*this)[i] || ar2[i]) num++;
	}
	return num;
}
template <class T> template <class T2> inline void array<T>::XOR(array<T2>& ar2){
   size_type len=std::min(this->size(),ar2.size());
   size_type i;
   for (i=0;i<len;i++){
      (*this)[i]=((*this)[i] || ar2[i]) && !((*this)[i] && ar2[i]);
   }
}
template <class T> template <class T2> inline size_type array<T>::XORnz(array<T2>& ar2){
   size_type len=std::min(this->size(),ar2.size());
   size_type i;
   size_type num=0;
   for (i=0;i<len;i++){
      if (((*this)[i] || ar2[i]) && !((*this)[i] && ar2[i])) num++;
   }
   return num;
}
template <class T> template <class T2> inline void array<T>::subSet(array<T2>& ar2){
	size_type len=std::min(this->size(),ar2.size());
	size_type i;
	for (i=0;i<len;i++){
		if (ar2[i]) (*this)[i]=0;
	}
}
template <class T> template <class T2> inline size_type array<T>::subSetnz(array<T2>& ar2){
	size_type len=std::min(this->size(),ar2.size());
	size_type i;
	size_type num=0;
	for (i=0;i<len;i++){
		if ((*this)[i] && (!(ar2[i]))) num++;
	}
	return num;
}
#endif
#endif
